home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / mail / mh / contrib / jpeek / mail.sort < prev    next >
Text File  |  1992-08-08  |  7KB  |  220 lines

  1. #! /bin/sh
  2. # $Header: /home/jerry/.bin/RCS/mail.sort,v 3.6 92/08/09 23:26:31 jerry mh_contrib $
  3. ###    mail.sort - sort mail messages in place, or link to temporary folder
  4. ###    Usage: mail.sort [folder] [-verbose] [-help] [-link [msgs]] [-c|f|o|s|t|x]"
  5. ##
  6. ##    THE sortm(1) PROGRAM FROM MH 6.6 CAN SORT MAIL MESSAGES BY
  7. ##    DATE.  BUT IF YOU WANT TO GROUP ORIGINAL MESSAGES WITH THEIR
  8. ##    REPLIES, OR SORT BY THE PERSON WHO SENT THEM, YOU CAN USE THIS
  9. ##    SCRIPT.  (THE MH 6.7 sortm IS MORE POWERFUL--AND IT DOES A LOT,
  10. ##    BUT NOT ALL, OF WHAT mail.sort DOES.)
  11. ##
  12. ##    mail.sort CAN SORT BY SUBJECT, IGNORING THE Re: SO THAT REPLIES
  13. ##    ARE GROUPED WITH THE ORIGINAL MESSAGE.  IT CAN SORT BY THE
  14. ##    Sender:, IF THERE IS ONE-- OTHERWISE, BY THE From:.  THERE ARE 6
  15. ##    OTHER WAYS TO SORT, AS WELL.
  16. ##
  17. ##    mail.sort USES scan FORMAT STRINGS TO PULL HEADER INFORMATION
  18. ##    OUT OF EACH MESSAGE.  SO, IF YOU CAN WRITE A FORMAT STRING, YOU
  19. ##    CAN SORT BY IT.  IF THERE'S A FORMAT STRING THAT YOU USE A LOT,
  20. ##    YOU CAN ADD A NEW OPTION TO mail.sort (BY ADDING A SINGLE LINE
  21. ##    OF CODE) THAT LETS YOU USE THAT FORMAT STRING ANY TIME, JUST BY
  22. ##    TYPING YOUR NEW OPTION ON THE COMMAND LINE.
  23. ##
  24. ##    BY DEFAULT, mail.sort SORTS MESSAGES AND PUTS THEM BACK IN THE
  25. ##    SAME FOLDER.  IT CAN ALSO LINK ALL THE MESSAGES INTO A TEMPORARY
  26. ##    SUB-FOLDER WITHOUT CHANGING THE SOURCE FOLDER ORDER.  WHEN
  27. ##    YOU'RE DONE WITH THE SUB-FOLDER, YOU CAN REMOVE IT.
  28. ##
  29. ##    THE -v OPTION WRITES VERBOSE INFO ABOUT WHAT'S HAPPENING TO stdout.
  30. #
  31. #    NOTE TO HACKERS: TABSTOPS SET AT 4 IN THIS CODE
  32. #
  33. #    USE AT YOUR OWN RISK.  SEEMS TO WORK, BUT IT'S YOUR RESPONSIBILITY!
  34. #    PLEASE TELL ME ABOUT BUGS AND FIXES: Jerry Peek, jerry@ora.com
  35.  
  36. umask 77                                            # PROTECT TEMPORARY FILE
  37. folopts="-nolist -nototal"                            # OVERRIDE MH PROFILE
  38. mh=/usr/local/mh                                    # WHERE MH COMMANDS LIVE
  39. myname="`basename $0`"                                # THIS PROGRAM'S NAME
  40. scanopts="-width 200 -noclear -noheader -noreverse"    # OVERRIDE MH PROFILE
  41. stat=1    # DEFAULT EXIT STATUS; RESET TO 0 BEFORE NORMAL exit
  42. subfol=MAILSORT$$                                    # TEMPORARY SUB-FOLDER
  43. temp=/tmp/MSORT$$
  44. usage="Usage: $myname [folder] [-verbose] [-help] [-link [msgs]] [-c|f|o|s|t|x]"
  45.  
  46. # trapS COME LATER... SEE BELOW.
  47.  
  48. what=/bin/mv    # DEFAULT IF NO -link
  49. for arg
  50. do
  51.     case "$arg" in
  52.     [+@]*) folder="$arg" ;;
  53.     -h*) echo "$usage
  54.  
  55.     Replaces messages in same folder unless you use -link,
  56.     when messages are linked into a sorted sub-folder.
  57.  
  58.     Sorts by Subject with Re:'s stripped,
  59.     unless you use one of the following:
  60.        -f[rom]
  61.        -s[ender]
  62.        -o[rigin]   (Sender, otherwise From)
  63.        -t[o]
  64.        -c[c]
  65.        -r[eply-to]
  66.        -x          (exact Subject, including Re:'s)
  67.  
  68.     $myname, \$Revision: 3.6 $ \$Date: 92/08/09 23:26:31 $"
  69.         stat=0
  70.         exit
  71.         ;;
  72.     -l*) what=/bin/ln ;;
  73.     -v*) vflag=y ;;
  74.     -*)    # SET COMPONENT TO SORT ON:
  75.         case "$how" in
  76.         ?*)    echo "$myname: '$arg'?  Only one of -c, -f, -o, -s, -t, -x." 1>&2
  77.             exit
  78.             ;;
  79.         esac
  80.         # NO DATE SORT HERE BECAUSE sortm DOES THAT, AND FASTER...
  81.         case "$arg" in
  82.         -f*) how='%(mbox{from})' ;; # FROM (mbox)
  83.         -s*) how='%(mbox{sender})' ;; # SENDER (mbox)
  84.         -t*) how='%(mbox{to})' ;; # TO (IGNORE MUTIPLE ADDRESSES)
  85.         -c*) how='%(mbox{cc})' ;; # CC (IGNORE MUTIPLE ADDRESSES)
  86.         -r*) how='%(mbox{reply-to})' ;; # REPLY-TO (mbox)
  87.         -x*) how='%{subject})' ;; # EXACT SUBJECT (INCLUDE Re:)
  88.         -o*) # SORT BY Sender, IF THERE IS ONE, OTHERWISE BY From:
  89.              how='%<{sender}%(mbox{sender})%|%(mbox{from})%>'
  90.              ;;
  91.         *)    echo "$usage
  92.             (invalid switch '$arg')" 1>&2
  93.             exit
  94.             ;;
  95.         esac
  96.         ;;
  97.     *)    # ONLY ALLOW MESSAGE ARGUMENTS IF LINKING; CAN RUIN FOLDER OTHERWISE:
  98.         case "$what" in
  99.         *ln) msgargs="$msgargs $arg" ;;
  100.         *)    echo "$usage
  101.             ('$arg'?  No message numbers unless using -link.)" 1>&2
  102.             exit 1
  103.             ;;
  104.         esac
  105.         ;;
  106.     esac
  107. done
  108.  
  109. origfol="`$mh/folder $folopts $folder -fast`"
  110. cd `$mh/mhpath +$origfol` || exit
  111.  
  112. # SET trapS THAT TELL USER HOW TO RECOVER WHEN stat != 1:
  113. trap 'echo "$myname: Interrupted." 1>&2' 1 2 15
  114. case "$what" in
  115. *ln) # SPECIAL MESSAGE FOR LINKING:
  116.    trap 'case "$stat" in 1) echo "$myname: You should run:
  117.    rmf +$origfol/$subfol" 1>&2;; esac;
  118.    rm -f $temp; exit $stat' 0
  119.    ;;
  120. *) trap 'case "$stat" in 1) echo "$myname:  Recover with:
  121.    folder +$origfol/$subfol
  122.    refile all @..
  123.    folder        (be sure +$origfol/$subfol is empty)
  124.    rmf           (remove +$origfol/$subfol)" 1>&2;; esac' 0
  125.    ;;
  126. esac
  127.  
  128. mkdir $subfol || exit
  129.  
  130. exec 3>&2        # SAVE ORIGINAL stderr; WE RESTORE IT LATER
  131. exec 2>$temp    # THROW stderr MESSAGES INTO $temp; TEST AT END OF THIS MESS
  132.  
  133. case "$vflag" in
  134. y) echo "$myname: sorting messages to temporary folder..." ;;
  135. esac
  136. # START LONG PIPELINE TO GET LIST OF MESSAGES, WITH OLD AND NEW NUMBERS.
  137. # SPIT MESSAGE NUMBERS AND TEXT FIELD TO STANDARD OUTPUT OF case.
  138. case "$how" in
  139. "") # SORT BY SUBJECT (DEFAULT); STRIP OFF "Re:", "RE:", "Re: Re:", ETC:
  140.     $mh/scan $scanopts -format '%(msg)#%{subject}' $msgargs |
  141.     sed -n '
  142.     /^[1-9][0-9]*#[Rr][Ee]:/ {
  143.     :rezap
  144.         s/^\([1-9][0-9]*#\)[Rr][Ee]: */\1/
  145.         /^[1-9][0-9]*#[Rr][Ee]:/b rezap
  146.     }
  147.     p'
  148.     ;;
  149. *)    # SORT BY WHATEVER ELSE (FORMAT STRING IS IN $how):
  150.     $mh/scan $scanopts -format "%(msg)#$how" $msgargs
  151.     ;;
  152. esac |
  153. sort -t\# +1 |    # SORT BY TEXT FIELD
  154. awk '{ kut = index($0, "#")    # ADD NEW MESSAGE NUMBERS, REMOVE "#"
  155.     print NR, substr($0, 1, kut-1), substr($0, kut+1) }' |
  156. while read new old text
  157. do
  158.     # MOVE OR LINK MESSAGES INTO SUB-FOLDER, ONE BY ONE.
  159.     #
  160.     # IF MESSAGE WAS UNREADABLE, scan PRINTED A LINE (TO STANDARD
  161.     # OUTPUT!) LIKE THIS, WITH LEADING BLANKS UNLESS msgnum > 999:
  162.     #   <msgnum>  unreadable
  163.     # WE GET THAT WITH A LINE NUMBER IN FRONT FROM awk...
  164.     # IF THERE ARE LEADING BLANKS, SOME BOURNE SHELLS WILL COPY ALL
  165.     # THIS STUFF INTO $text, AND LEAVE BOTH $new AND $old
  166.     # EMPTY.  TRY TO CATCH BOTH CASES:
  167.     case "$new" in
  168.     "")    echo "$myname: message $new $old $text" 1>&2; break ;;
  169.     esac
  170.     case "$text" in
  171.     unreadable)    echo "$myname: can't read msg '$old'???" 1>&2; break ;;
  172.     esac
  173.     # USE UNIX COMMANDS; AVOID ALL THE OVERHEAD THAT refile WOULD ADD:
  174.     if $what $old $subfol/$new
  175.     then
  176.         case "$vflag" in
  177.         y) echo "$myname: old #$old --> new #$new ($text)" ;;
  178.         esac
  179.     else
  180.         echo "$myname: '$what $old $subfol/$new' failed." 1>&2
  181.         break
  182.     fi
  183. done
  184. exec 2>&-    # CLOSE TEMPORARY stderr
  185. exec 2>&3    # RESTORE ORIGINAL stderr
  186.  
  187. # IF THERE WERE ANY ERRORS IN THE MESS ABOVE, SHOW THEM AND EXIT:
  188. if test -s $temp
  189. then
  190.     echo "$myname: quitting:" 1>&2
  191.     cat $temp 1>&2
  192.     exit
  193. fi
  194.  
  195. set -e    # exit IF ANY ERROR FROM NOW ON
  196.  
  197. case "$what" in
  198. *ln)
  199.     case "$vflag" in
  200.     y)    $mh/folder @$subfol
  201.         echo "$myname: done."
  202.         echo "When you're done with this sub-folder, type 'rmf' to remove it."
  203.         ;;
  204.     *)    $mh/folder -fast @$subfol >/dev/null ;;
  205.     esac
  206.     ;;
  207. *)
  208.     # cd TO SUB-FOLDER AVOIDS LONG PATHNAMES (& COMMAND LINE OVERFLOW):
  209.     cd $subfol
  210.     case "$vflag" in
  211.     y) echo "$myname: moving messages back to original folder..." ;;
  212.     esac
  213.     /bin/mv * ..
  214.     cd ..
  215.     /bin/rmdir $subfol
  216.     ;;
  217. esac
  218. stat=0
  219. exit
  220.